package com.yunxi.poc.starbucks.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.yunxi.poc.starbucks.common.BizConstant;
import com.yunxi.poc.starbucks.entity.*;
import com.yunxi.poc.starbucks.service.IOrderService;
import com.yunxi.poc.starbucks.service.IScrowdedService;
import com.yunxi.poc.starbucks.service.ITStoreCapacityService;
import com.yunxi.poc.starbucks.service.ITb1TransactionSaleService;
import com.yunxi.poc.starbucks.util.CacheUtil;
import com.yunxi.poc.starbucks.util.DateUtil;
import com.yunxi.poc.starbucks.vo.StoreRateVO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Month;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class ScrowdedServiceImpl implements IScrowdedService {

    private final static Logger logger = LoggerFactory.getLogger(ScrowdedServiceImpl.class);

    @Resource
    ITStoreCapacityService tStoreCapacityService;

    @Resource
    IOrderService orderService;

    @Resource
    ITb1TransactionSaleService tb1TransactionSaleService;

    @Override
    public double scoreScrowded(Tb1Store store, LocalDateTime current, StoreRateVO calRes) {
        // double efficiency = this.efficiency(current.toLocalDate(), store, BizConstant.SCROWDED_EFFICIENCY_DAYS, calRes);
        // double coffeeQueue = this.waitingCoffee(current, store, efficiency, calRes);
        // double crowdedRate = efficiency == 0 ? 0 : Math.max(coffeeQueue / efficiency - BizConstant.SCROWDED_WAIT_MINUTE, 0);

        double crowdedRate = this.waitingCoffeeByQueueWithTime(current, store, calRes);

        // calRes.setScrowdedEfficiency(String.valueOf(efficiency));
        // calRes.setScrowdedCoffeeQueue(String.valueOf(coffeeQueue));

        return new BigDecimal(crowdedRate).setScale(2, RoundingMode.DOWN).doubleValue();
    }

    @Override
    public double efficiency(LocalDate current, Tb1Store store, int days, StoreRateVO calRes) {
        QueryWrapper<TStoreCapacity> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("max20min_sales", "daily_sales", "business_day");
        // 固定获取5月对应的产能数据
//        queryWrapper.ge("business_day", current.minusDays(days));
//        queryWrapper.lt("business_day", current);
        queryWrapper.ge("business_day", LocalDate.of(BizConstant.SCROWDED_CAPACITY_YEAR, Month.of(BizConstant.SCROWDED_CAPACITY_MONTH), BizConstant.SCROWDED_CAPACITY_DAY_OF_MONTH_START));
        queryWrapper.le("business_day", LocalDate.of(BizConstant.SCROWDED_CAPACITY_YEAR, Month.of(BizConstant.SCROWDED_CAPACITY_MONTH), BizConstant.SCROWDED_CAPACITY_DAY_OF_MONTH_END));
        queryWrapper.eq("store_id", store.getGlobalStoreNumber());
        List<TStoreCapacity> storeCapacities = tStoreCapacityService.list(queryWrapper);
        if (CollectionUtils.isEmpty(storeCapacities)) {
            // calRes.setTag("WARN");
            calRes.getMsg().add("func.efficiency.warn: " + "no TStoreCapacity records found, set default " + BizConstant.SCROWDED_EFFICIENCY_DEFAULT_MIN);
            return BizConstant.SCROWDED_EFFICIENCY_DEFAULT_MIN;
        }

        // 过滤不营业门店 最近三天销量<10 说明不营业，进行过滤；
//        double lastSales = storeCapacities.stream()
//                .filter((e) -> ChronoUnit.DAYS.between(e.getBusinessDay(), current) <= BizConstant.SCROWDED_CAPACITY_DAYS)
//                .mapToDouble(TStoreCapacity::getDailySales)
//                .sum();
//        if (lastSales <= BizConstant.SCROWDED_CAPACITY_DAYS * 10) {
//            calRes.setTag("WARN");
//            calRes.getMsg().add("func.efficiency.warn:" + " last " + BizConstant.SCROWDED_CAPACITY_DAYS + " days capacity less than " + BizConstant.SCROWDED_CAPACITY_DAYS * 10);
//            return BizConstant.SCROWDED_EFFICIENCY_DEFAULT;
//        }

        double efficiency = storeCapacities.stream()
                .mapToDouble(e -> Double.parseDouble(e.getMax20minSales()))
                .max()
                .orElse(0);

        // 比较标准产能
        efficiency = Math.max(efficiency, BizConstant.SCROWDED_EFFICIENCY_DEFAULT_MIN);

        return new BigDecimal(efficiency).setScale(2, RoundingMode.DOWN).doubleValue();
    }

    @Override
    public double waitingCoffee(LocalDateTime current, Tb1Store store, double efficiency, StoreRateVO calRes) {
        return "queue".equals(BizConstant.SCROWDED_WAITINGCOFFEE_TYPE) ?
                this.waitingCoffeeByQueue(current, store, efficiency, calRes) :
                this.waitingCoffeeByOnlineOrder(current, store, efficiency, calRes);
    }

    @Override
    public double waitingCoffeeByQueue(LocalDateTime current, Tb1Store store, double efficiency, StoreRateVO calRes) {
        // 默认；订单队列获取开始时间为营业开始时间
        LocalDateTime queueStartAt = LocalDateTime.of(current.getYear(), current.getMonth(), current.getDayOfMonth(),
                BizConstant.SCROWDED_OPEN_TIME, 0, 0);

        // 获取【当天门店营业时间】为【队列开始时间】
        List<Tb1StoreOpen> storeOpensToday = CacheUtil.storeOpens.stream().filter(e ->
                        store.getGlobalStoreNumber().equals(e.getGlobalId()) && current.getDayOfWeek().getValue() == e.getDayOfWeekMon1Sun7())
                .collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(storeOpensToday)) {
            queueStartAt = LocalDateTime.of(current.getYear(), current.getMonth(),
                    current.getDayOfMonth(), storeOpensToday.get(0).getBusinessOpenTime().getHour(), storeOpensToday.get(0).getBusinessOpenTime().getMinute(), storeOpensToday.get(0).getBusinessOpenTime().getSecond());
            calRes.setScrowdedStoreOpenAt(queueStartAt.toString());
        }

        // 获取昨天门店营业时间，如果【当天门店营业开始时间】往前推一个小时【晚于】【昨天门店营业结束时间】
        List<Tb1StoreOpen> storeOpensYesterday = CacheUtil.storeOpens.stream().filter(e ->
                        store.getGlobalStoreNumber().equals(e.getGlobalId()) && current.minusDays(1).getDayOfWeek().getValue() == e.getDayOfWeekMon1Sun7())
                .collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(storeOpensYesterday)) {
            LocalDateTime yesterdayClosedTime = LocalDateTime.of(current.minusDays(1).getYear(), current.minusDays(1).getMonth(),
                    current.minusDays(1).getDayOfMonth(), storeOpensYesterday.get(0).getBusinessCloseTime().getHour(), storeOpensYesterday.get(0).getBusinessCloseTime().getMinute(), storeOpensYesterday.get(0).getBusinessCloseTime().getSecond());
            if (queueStartAt.minusHours(1).isAfter(yesterdayClosedTime)) queueStartAt = queueStartAt.minusHours(1);
        }

        // get the latest make finish order
        // Order latestMakeFinishOrder = orderService.getLatestMakeFinishOrder(current, store.getGlobalStoreNumber());

        // 队列初始数量，最近一笔制作完成订单的制作耗时
        double initQueueNum = 0, minBetween;

        // 当天存在【最近一笔制作完成订单】，如果下单时间早于开店时间，则从开店时间计算
//        if (!ObjectUtils.isEmpty(latestMakeFinishOrder) && latestMakeFinishOrder.getCreateDate().toLocalDate().compareTo(current.toLocalDate()) == 0) {
//            LocalDateTime orderStartAt = queueStartAt.compareTo(latestMakeFinishOrder.getCreateDate()) > 0 ? queueStartAt : latestMakeFinishOrder.getCreateDate();
//            minBetween = Math.abs(ChronoUnit.MINUTES.between(orderStartAt, latestMakeFinishOrder.getMakeFinishDate()));
//            initQueueNum = minBetween * efficiency;
//            queueStartAt = orderStartAt;
//
//            calRes.setScrowdedFinalOrderId(String.valueOf(latestMakeFinishOrder.getId()));
//            calRes.setScrowdedFinalOrderMakeFinishDate(latestMakeFinishOrder.getMakeFinishDate().toString());
//            calRes.setScrowdedFinalOrderCreateDate(latestMakeFinishOrder.getCreateDate().toString());
//            calRes.setScrowdedFinalOrderMakeCostTime(String.valueOf(minBetween));
//        }

        calRes.setScrowdedQueueStartAt(queueStartAt.toString());
        calRes.setScrowdedQueueInitNum(String.valueOf(initQueueNum));

        // 获取一段时间内的全部订单
        QueryWrapper<Tb1TransactionSale> queryWrapperTrans = new QueryWrapper<>();
        queryWrapperTrans.select("sale_item_quantity", "sale_datetime");
        queryWrapperTrans.eq("global_store_number", store.getGlobalStoreNumber());
        queryWrapperTrans.ge("sale_datetime", queueStartAt);
        queryWrapperTrans.le("sale_datetime", current);
        queryWrapperTrans.last("AND sale_item_code "
                + "in ( SELECT distinct sale_item_code FROM saleitem_with_reportcategory "
                + "where report_category in ("
                + BizConstant.REPORT_CATEGORY.stream().map(e -> "'" + e + "'").collect(Collectors.joining(","))
                + ") )");
        List<Tb1TransactionSale> tb1TransactionSales = this.tb1TransactionSaleService.list(queryWrapperTrans);

        // 无订单，返回0
        if (tb1TransactionSales.size() == 0) {
            calRes.getMsg().add("func.waitingCoffee.warn: " + "no trans found, set waiting coffees 0");
            calRes.setScrowdedRecentOrdersProductNum("0");
            return 0;
        }

        // 排序
        tb1TransactionSales.sort(Comparator.comparing(Tb1TransactionSale::getSaleDatetime));

        // 累计队列初始数量到第一单
        tb1TransactionSales.get(0).setSaleItemQuantity(tb1TransactionSales.get(0).getSaleItemQuantity().add(BigDecimal.valueOf(initQueueNum)));

        calRes.setScrowdedRecentOrdersProductNum(
                String.valueOf(tb1TransactionSales.stream()
                        .mapToDouble(e -> e.getSaleItemQuantity().setScale(2, RoundingMode.DOWN).doubleValue())
                        .sum()));
        // 消费订单队列
        LocalDateTime start = queueStartAt;
        List<Tb1TransactionSale> filterTransLeft = new ArrayList<>();
        while (start.compareTo(current) <= 0) {
            double efficiencyTmp = efficiency;
            LocalDateTime starTmp = start;

            // 过滤时间范围内的订单
            List<Tb1TransactionSale> filterTrans = tb1TransactionSales.stream()
                    .filter((e) -> e.getSaleDatetime().isAfter(starTmp.minusSeconds(1)) && e.getSaleDatetime().isBefore(starTmp.plusSeconds(60 + 1)))
                    .collect(Collectors.toList());

            // logger.info(starTmp + " " + starTmp.plusSeconds(60) + " queue: " + filterTrans.size());

            // 累加订单
            filterTransLeft.addAll(filterTrans);
            filterTransLeft.sort(Comparator.comparing(Tb1TransactionSale::getSaleDatetime));

            // 时间滑动1分钟
            start = start.plusSeconds(60);

            // 边界条件：无订单
            if (filterTransLeft.size() == 0) continue;

            while (efficiencyTmp > 0) {
                if (filterTransLeft.size() > 0) {
                    double saleQuatity = filterTransLeft.get(0).getSaleItemQuantity().setScale(2, RoundingMode.DOWN).doubleValue();
                    if (saleQuatity > efficiencyTmp) {
                        filterTransLeft.get(0).setSaleItemQuantity(BigDecimal.valueOf(saleQuatity - efficiencyTmp));
                    }
                    if (saleQuatity <= efficiencyTmp) {
                        filterTransLeft.remove(0);
                    }
                    efficiencyTmp = Math.max(efficiencyTmp - saleQuatity, 0);
                } else {
                    efficiencyTmp = 0;
                }
            }

            // logger.info(starTmp + " " + starTmp.plusSeconds(60) + " queue left: " + filterTransLeft.size());
        }

        return filterTransLeft.stream()
                .mapToDouble(e -> e.getSaleItemQuantity().setScale(2, RoundingMode.DOWN).doubleValue())
                .sum();
    }

    @Override
    public double waitingCoffeeByQueueWithTime(LocalDateTime current, Tb1Store store, StoreRateVO calRes) {
        // 默认；订单队列获取开始时间为营业开始时间
        LocalDateTime queueStartAt = LocalDateTime.of(current.getYear(), current.getMonth(), current.getDayOfMonth(),
                BizConstant.SCROWDED_OPEN_TIME, 0, 0);

        // 获取【当天门店营业时间】为【队列开始时间】
        List<Tb1StoreOpen> storeOpensToday = CacheUtil.storeOpens.stream().filter(e ->
                        store.getGlobalStoreNumber().equals(e.getGlobalId()) && current.getDayOfWeek().getValue() == e.getDayOfWeekMon1Sun7())
                .collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(storeOpensToday)) {
            queueStartAt = LocalDateTime.of(current.getYear(), current.getMonth(),
                    current.getDayOfMonth(), storeOpensToday.get(0).getBusinessOpenTime().getHour(), storeOpensToday.get(0).getBusinessOpenTime().getMinute(), storeOpensToday.get(0).getBusinessOpenTime().getSecond());
            calRes.setScrowdedStoreOpenAt(queueStartAt.toString());
        }

        // 获取昨天门店营业时间，如果【当天门店营业开始时间】往前推一个小时【晚于】【昨天门店营业结束时间】
        List<Tb1StoreOpen> storeOpensYesterday = CacheUtil.storeOpens.stream().filter(e ->
                        store.getGlobalStoreNumber().equals(e.getGlobalId()) && current.minusDays(1).getDayOfWeek().getValue() == e.getDayOfWeekMon1Sun7())
                .collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(storeOpensYesterday)) {
            LocalDateTime yesterdayClosedTime = LocalDateTime.of(current.minusDays(1).getYear(), current.minusDays(1).getMonth(),
                    current.minusDays(1).getDayOfMonth(), storeOpensYesterday.get(0).getBusinessCloseTime().getHour(), storeOpensYesterday.get(0).getBusinessCloseTime().getMinute(), storeOpensYesterday.get(0).getBusinessCloseTime().getSecond());
            if (queueStartAt.minusHours(1).isAfter(yesterdayClosedTime)) queueStartAt = queueStartAt.minusHours(1);
        }
        // 队列初始数量，最近一笔制作完成订单的制作耗时
        double initQueueNum = 0;

        calRes.setScrowdedQueueStartAt(queueStartAt.toString());
        calRes.setScrowdedQueueInitNum(String.valueOf(initQueueNum));

        // 获取一段时间内的全部订单
        QueryWrapper<Tb1TransactionSale> queryWrapperTrans = new QueryWrapper<>();
        queryWrapperTrans.select("sale_item_quantity", "sale_datetime");
        queryWrapperTrans.eq("global_store_number", store.getGlobalStoreNumber());
        queryWrapperTrans.ge("sale_datetime", queueStartAt);
        queryWrapperTrans.le("sale_datetime", current);
        queryWrapperTrans.last("AND sale_item_code "
                + "in ( SELECT distinct sale_item_code FROM saleitem_with_reportcategory "
                + "where report_category in ("
                + BizConstant.REPORT_CATEGORY.stream().map(e -> "'" + e + "'").collect(Collectors.joining(","))
                + ") )");
        List<Tb1TransactionSale> tb1TransactionSales = this.tb1TransactionSaleService.list(queryWrapperTrans);

        // 无订单，返回0
        if (tb1TransactionSales.size() == 0) {
            calRes.getMsg().add("func.waitingCoffee.warn: " + "no trans found, set waiting minutes 0");
            calRes.setScrowdedRecentOrdersProductNum("0");
            return 0;
        }

        // 排序
        tb1TransactionSales.sort(Comparator.comparing(Tb1TransactionSale::getSaleDatetime));

        // 累计队列初始数量到第一单
        tb1TransactionSales.get(0).setSaleItemQuantity(tb1TransactionSales.get(0).getSaleItemQuantity().add(BigDecimal.valueOf(initQueueNum)));

        calRes.setScrowdedRecentOrdersProductNum(
                String.valueOf(tb1TransactionSales.stream()
                        .mapToDouble(e -> e.getSaleItemQuantity().setScale(2, RoundingMode.DOWN).doubleValue())
                        .sum()));


        DayOfWeek dayOfMonth = tb1TransactionSales.get(0).getSaleDatetime().getDayOfWeek();
        // 产能参考月份
        LocalDateTime baseCapacityDate =
                BizConstant.SCROWDED_CAPACITY_REFER_SWITCH ?
                        this.getLastDayOfWeek(tb1TransactionSales.get(0).getSaleDatetime().withYear(BizConstant.SCROWDED_CAPACITY_YEAR).withMonth(BizConstant.SCROWDED_CAPACITY_MONTH).withDayOfMonth(BizConstant.SCROWDED_CAPACITY_DAY_OF_MONTH_END), dayOfMonth)
                        :
                        this.getLastDayOfWeek(tb1TransactionSales.get(0).getSaleDatetime().minusDays(1), dayOfMonth);
        // 包含当天 过去4周同一天的产能
        List<LocalDate> businuessDays = new ArrayList<>(20);
        businuessDays.add(tb1TransactionSales.get(0).getSaleDatetime().toLocalDate());
        Arrays.asList(0, 1, 2, 3).parallelStream().forEach(i -> {
            LocalDateTime compareDateTime = baseCapacityDate.minusDays(i * 7L);
            businuessDays.add(compareDateTime.toLocalDate());
        });


        LocalDateTime start = queueStartAt;
        // 初始产能
        double efficiencyDinamic = this.efficiencyDinamic(tb1TransactionSales.get(0).getSaleDatetime(), store.getGlobalStoreNumber(), baseCapacityDate, businuessDays);
        // 初始时间区间对
        List<LocalDateTime> lastTimePair = DateUtil.getTimePair(tb1TransactionSales.get(0).getSaleDatetime(), 0);
        // int i = 0;
        // logger.info("[store]" + store.getGlobalStoreNumber() + " [start at]" + tb1TransactionSales.get(0).getSaleDatetime().toString() +
        //         " [time pair]" + (++i) + "->" + lastTimePair.get(0).toString() + "-" + lastTimePair.get(1).toString() + " [capacity]" + efficiencyDinamic);
        // 消费订单队列
        for (Tb1TransactionSale tb1TransactionSale : tb1TransactionSales) {
            // 订单商品数量 时间
            BigDecimal quantity = tb1TransactionSale.getSaleItemQuantity();
            LocalDateTime saleDatetime = tb1TransactionSale.getSaleDatetime();
            // 动态获取历史对应时间产能
            if (saleDatetime.toLocalTime().isAfter(lastTimePair.get(1).toLocalTime())) {
                lastTimePair = DateUtil.getTimePair(saleDatetime, 0);
                efficiencyDinamic = this.efficiencyDinamic(saleDatetime, store.getGlobalStoreNumber(), baseCapacityDate, businuessDays);
                //     logger.info("[store]" + store.getGlobalStoreNumber() + " [start at]" + saleDatetime.toString() +
                //             " [time pair]" + (++i) + "->" + lastTimePair.get(0).toString() + "-" + lastTimePair.get(1).toString() + " [capacity]" + efficiencyDinamic);
            }
            // 模拟订单耗时（秒）
            double costSecs = (quantity.doubleValue() / efficiencyDinamic) * 60;
            // 模拟订单处理开始时间
            LocalDateTime orderCreateDateMock = start.isAfter(saleDatetime) ? start : saleDatetime;
            // 模拟订单处理结束时间
            start = orderCreateDateMock.plusSeconds((long) costSecs);
        }

        calRes.setScrowdedQueueEndAt(start.toString());

        if (start.isBefore(current)) return 0;

        return Math.max((Math.abs(ChronoUnit.SECONDS.between(start, current)) / 60) - BizConstant.SCROWDED_WAIT_MINUTE, 0);
    }

    @Override
    public double waitingCoffeeByOnlineOrder(LocalDateTime current, Tb1Store store, double efficiency, StoreRateVO calRes) {
        // get the latest make finish order
        Order latestMakeFinishOrder = orderService.getLatestMakeFinishOrder(current, store.getGlobalStoreNumber());

        // 当天8点
        LocalDateTime lastMakeFinishDate = LocalDateTime.of(current.getYear(), current.getMonth(),
                current.getDayOfMonth(), BizConstant.SCROWDED_OPEN_TIME, 0, 0);

        double sales;

        // 最近一笔线上订单的制作完成时间不在当天
        if (ObjectUtils.isEmpty(latestMakeFinishOrder) || latestMakeFinishOrder.getMakeFinishDate().getDayOfWeek() != current.getDayOfWeek()) {
            // get transactions sales between [当天8点] and current
            sales = tb1TransactionSaleService.calculateSales(
                    Arrays.asList(Integer.valueOf(store.getGlobalStoreNumber())),
                    lastMakeFinishDate,
                    current);
        } else {
            lastMakeFinishDate = latestMakeFinishOrder.getMakeFinishDate();
            // get transactions sales between orders.get(0).create_date and current
            sales = tb1TransactionSaleService.calculateSales(
                    Arrays.asList(Integer.valueOf(store.getGlobalStoreNumber())),
                    latestMakeFinishOrder.getCreateDate(),
                    current);

            calRes.setScrowdedFinalOrderId(String.valueOf(latestMakeFinishOrder.getId()));
            calRes.setScrowdedFinalOrderMakeFinishDate(latestMakeFinishOrder.getMakeFinishDate().toString());
            calRes.setScrowdedFinalOrderCreateDate(latestMakeFinishOrder.getCreateDate().toString());
        }

        if (sales == 0) {
            calRes.setTag("WARN");
            calRes.getMsg().add("no sales today");
        }

        // Δ minutes diff
        long minBetween = Math.abs(ChronoUnit.MINUTES.between(lastMakeFinishDate, current));

        calRes.setScrowdedFinalOrderUntilNowMins(String.valueOf(minBetween));
        calRes.setScrowdedFinalOrderUndoneNum(String.valueOf(sales));

        return Math.max(sales - minBetween * efficiency, 0);
    }

    @Override
    public double efficiencyDinamic(LocalDateTime orderDateTime, String storeId, LocalDateTime baseCapacityDate, List<LocalDate> businuessDays) {

        if (!CacheUtil.storesCapacity.containsKey(storeId)) return BizConstant.SCROWDED_EFFICIENCY_DEFAULT_MIN;

        // 订单时间对应周几
        DayOfWeek dayOfMonth = orderDateTime.getDayOfWeek();
        LocalDate orderDate = orderDateTime.toLocalDate();

        // 当天上一个时间段
        // List<LocalDateTime> lastTimePair = DateUtil.getTimePair(orderDateTime, -1);

        // 产能参考月份
//        LocalDateTime baseCapacityDate =
//                BizConstant.SCROWDED_CAPACITY_REFER_SWITCH ?
//                        this.getLastDayOfWeek(orderDateTime.withYear(BizConstant.SCROWDED_CAPACITY_YEAR).withMonth(BizConstant.SCROWDED_CAPACITY_MONTH).withDayOfMonth(BizConstant.SCROWDED_CAPACITY_DAY_OF_MONTH_END), dayOfMonth)
//                        :
//                        this.getLastDayOfWeek(orderDateTime.minusDays(1), dayOfMonth);

        // 包含当天 过去4周同一天的产能
//        List<LocalDate> businuessDays = new ArrayList<>(20);
//        businuessDays.add(orderDate);

        // 区间对
        List<List<LocalDateTime>> pairs = new ArrayList<>(20);
        pairs.add(DateUtil.getTimePair(orderDateTime, -1));
        Arrays.asList(0, 1, 2, 3).parallelStream().forEach(i -> {
            LocalDateTime compareDateTime = baseCapacityDate.minusDays(i * 7L);
//            businuessDays.add(compareDateTime.toLocalDate());
            Arrays.asList(-1, 0, 1).parallelStream().forEach(index -> {
                List<LocalDateTime> timePair = DateUtil.getTimePair(compareDateTime, index);
                pairs.add(timePair);
            });
        });

        List<TStoreCapacity> storeCapacities = CacheUtil.storesCapacity.get(storeId).parallelStream()
                // .filter(e -> e.getStoreId().equals(storeId))
                // .filter(e -> !BizConstant.HOLIDAYS.contains(e.getBusinessDay()))
                .filter(e -> businuessDays.contains(e.getBusinessDay())).parallel()
                .filter(e -> {

                    Optional<List<LocalDateTime>> tag = pairs.parallelStream()
                            .filter(p -> e.getBusinessDay().isEqual(p.get(0).toLocalDate()) && e.getStart().equals(p.get(0).toLocalTime()) && e.getEnd().equals(p.get(1).toLocalTime()))
                            .findAny();

                    return tag.isPresent();

//                    // 取当天前一个是时间段产能进行矫正
//                    if (e.getBusinessDay().isEqual(orderDate) && e.getStart().equals(lastTimePair.get(0).toLocalTime()) && e.getEnd().equals(lastTimePair.get(1).toLocalTime())) {
//                        return true;
//                    }
//                    // 获取过去周期对应时间段的产能
//                    final boolean[] exists = {false};
//                    Arrays.asList(0, 1, 2, 3).parallelStream().forEach(i -> Arrays.asList(-1, 0, 1).parallelStream().forEach(index -> {
//                        LocalDateTime compareDateTime = baseCapacityDate.minusDays(i * 7L);
//                        List<LocalDateTime> timePair = DateUtil.getTimePair(compareDateTime, index);
//                        exists[0] = exists[0] || e.getBusinessDay().isEqual(compareDateTime.toLocalDate()) && e.getStart().equals(timePair.get(0).toLocalTime()) && e.getEnd().equals(timePair.get(1).toLocalTime());
//                    }));
//                    return exists[0];
                }).collect(Collectors.toList());

        // storeCapacities.forEach((e) -> {
        //     logger.info(e.getBusinessDay().toString() + " " + e.getStart().toString() + " " + e.getEnd().toString() + " " + e.getMax20minSales());
        // });

        double efficiency = storeCapacities.parallelStream().mapToDouble(e -> Double.parseDouble(e.getMax20minSales()))
                // .average()
                .max()
                .orElse(BizConstant.SCROWDED_EFFICIENCY_DEFAULT_MIN);

        efficiency = Math.min(BizConstant.SCROWDED_EFFICIENCY_DEFAULT_MAX, Math.max(BizConstant.SCROWDED_EFFICIENCY_DEFAULT_MIN, efficiency));

        return efficiency;
    }

    /**
     * 获取日期往前递减至 dayOfWeek 的时间
     *
     * @param dateTime
     * @param dayOfWeek
     * @return
     */
    private LocalDateTime getLastDayOfWeek(LocalDateTime dateTime, DayOfWeek dayOfWeek) {
        LocalDateTime compareDateTime = dateTime;
        if (compareDateTime.getDayOfWeek().compareTo(dayOfWeek) == 0) return compareDateTime;
        while (compareDateTime.minusDays(1).getDayOfWeek().compareTo(dayOfWeek) != 0) {
            compareDateTime = compareDateTime.minusDays(1);
        }
        return compareDateTime.minusDays(1);
    }

}
